///**
// * Copyright 2007-2010 Arthur Blake
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// *    http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//package net.sf.log4jdbc;
//
//import java.util.StringTokenizer;
//
//import org.slf4j.LoggerFactory;
//import org.slf4j.Logger;
//
///**
// * Delegates JDBC spy logging events to the the Simple Logging Facade for Java (slf4j).
// *
// * @author Arthur Blake
// */
//public class Slf4jSpyLogDelegator implements SpyLogDelegator
//{
//  /**
//   * Create a SpyLogDelegator specific to the Simple Logging Facade for Java (slf4j).
//   */
//  public Slf4jSpyLogDelegator()
//  {
//  }
//
//  // logs for sql and jdbc
//
//  /**
//   * Logger that shows all JDBC calls on INFO level (exception ResultSet calls)
//   */
//  private final Logger jdbcLogger = LoggerFactory.getLogger("jdbc.audit");
//
//  /**
//   * Logger that shows JDBC calls for ResultSet operations
//   */
//  private final Logger resultSetLogger = LoggerFactory.getLogger("jdbc.resultset");
//
//  /**
//   * Logger that shows only the SQL that is occuring
//   */
//  private final Logger sqlOnlyLogger = LoggerFactory.getLogger("jdbc.sqlonly");
//
//  /**
//   * Logger that shows the SQL timing, post execution
//   */
//  private final Logger sqlTimingLogger = LoggerFactory.getLogger("jdbc.sqltiming");
//
//  /**
//   * Logger that shows connection open and close events as well as current number
//   * of open connections.
//   */
//  private final Logger connectionLogger = LoggerFactory.getLogger("jdbc.connection");
//
//  // admin/setup logging for log4jdbc.
//
//  /**
//   * Logger just for debugging things within log4jdbc itself (admin, setup, etc.)
//   */
//  private final Logger debugLogger = LoggerFactory.getLogger("log4jdbc.debug");
//
//  /**
//   * Determine if any of the 5 log4jdbc spy loggers are turned on (jdbc.audit | jdbc.resultset |
//   * jdbc.sqlonly | jdbc.sqltiming | jdbc.connection)
//   *
//   * @return true if any of the 5 spy jdbc/sql loggers are enabled at debug info or error level.
//   */
//  public boolean isJdbcLoggingEnabled()
//  {
//    return jdbcLogger.isErrorEnabled() || resultSetLogger.isErrorEnabled() || sqlOnlyLogger.isErrorEnabled() ||
//      sqlTimingLogger.isErrorEnabled() || connectionLogger.isErrorEnabled();
//  }
//
//  /**
//   * Called when a jdbc method throws an Exception.
//   *
//   * @param spy        the Spy wrapping the class that threw an Exception.
//   * @param methodCall a description of the name and call parameters of the method generated the Exception.
//   * @param e          the Exception that was thrown.
//   * @param sql        optional sql that occured just before the exception occured.
//   * @param execTime   optional amount of time that passed before an exception was thrown when sql was being executed.
//   *                   caller should pass -1 if not used
//   */
//  public void exceptionOccured(Spy spy, String methodCall, Exception e, String sql, long execTime)
//  {
//    String classType = spy.getClassType();
//    Integer spyNo = spy.getConnectionNumber();
//    String header = spyNo + ". " + classType + "." + methodCall;
//    if (sql == null)
//    {
//      jdbcLogger.error(header, e);
//      sqlOnlyLogger.error(header, e);
//      sqlTimingLogger.error(header, e);
//    }
//    else
//    {
//      jdbcLogger.error(header + " " + sql, e);
//
//      // if at debug level, display debug info to error log
//      if (sqlOnlyLogger.isDebugEnabled())
//      {
//        sqlOnlyLogger.error(getDebugInfo() + nl + spyNo + ". " + sql, e);
//      }
//      else
//      {
//        sqlOnlyLogger.error(header + " " + sql, e);
//      }
//
//      // if at debug level, display debug info to error log
//      if (sqlTimingLogger.isDebugEnabled())
//      {
//        sqlTimingLogger.error(getDebugInfo() + nl + spyNo + ". " + sql + " {FAILED after " + execTime + " msec}", e);
//      }
//      else
//      {
//        sqlTimingLogger.error(header + " FAILED! " + sql + " {FAILED after " + execTime + " msec}", e);
//      }
//    }
//  }
//
//  /**
//   * Called when a JDBC method from a Connection, Statement, PreparedStatement,
//   * CallableStatement or ResultSet returns.
//   *
//   * @param spy        the Spy wrapping the class that called the method that
//   *                   returned.
//   * @param methodCall a description of the name and call parameters of the
//   *                   method that returned.
//   * @param returnMsg  return value converted to a String for integral types, or
//   *                   String representation for Object.  Return types this will
//   *                   be null for void return types.
//   */
//  public void methodReturned(Spy spy, String methodCall, String returnMsg)
//  {
//    String classType = spy.getClassType();
//    Logger logger=ResultSetSpy.classTypeDescription.equals(classType)?
//      resultSetLogger:jdbcLogger;
//    if (logger.isInfoEnabled())
//    {
//      String header = spy.getConnectionNumber() + ". " + classType + "." +
//        methodCall + " returned " + returnMsg;
//      if (logger.isDebugEnabled())
//      {
//        logger.debug(header + " " + getDebugInfo());
//      }
//      else
//      {
//        logger.info(header);
//      }
//    }
//  }
//
//  /**
//   * Called when a spied upon object is constructed.
//   *
//   * @param spy              the Spy wrapping the class that called the method that returned.
//   * @param constructionInfo information about the object construction
//   */
//  public void constructorReturned(Spy spy, String constructionInfo)
//  {
//    // not used in this implementation -- yet
//  }
//
//  private static String nl = System.getProperty("line.separator");
//
//  /**
//   * Determine if the given sql should be logged or not
//   * based on the various DumpSqlXXXXXX flags.
//   *
//   * @param sql SQL to test.
//   * @return true if the SQL should be logged, false if not.
//   */
//  private boolean shouldSqlBeLogged(String sql)
//  {
//    if (sql == null)
//    {
//      return false;
//    }
//    sql = sql.trim();
//
//    if (sql.length()<6)
//    {
//      return false;
//    }
//    sql = sql.substring(0,6).toLowerCase();
//    return
//      (DriverSpy.DumpSqlSelect && "select".equals(sql)) ||
//      (DriverSpy.DumpSqlInsert && "insert".equals(sql)) ||
//      (DriverSpy.DumpSqlUpdate && "update".equals(sql)) ||
//      (DriverSpy.DumpSqlDelete && "delete".equals(sql)) ||
//      (DriverSpy.DumpSqlCreate && "create".equals(sql));
//  }
//
//  /**
//   * Special call that is called only for JDBC method calls that contain SQL.
//   *
//   * @param spy        the Spy wrapping the class where the SQL occured.
//   * @param methodCall a description of the name and call parameters of the method that generated the SQL.
//   * @param sql        sql that occured.
//   */
//  public void sqlOccured(Spy spy, String methodCall, String sql)
//  {
//    if (!DriverSpy.DumpSqlFilteringOn || shouldSqlBeLogged(sql))
//    {
//      sql = processSql(sql);
//
//      if (sqlOnlyLogger.isDebugEnabled())
//      {
//        sqlOnlyLogger.debug(getDebugInfo() + nl + spy.getConnectionNumber() + ". " + sql);
//      }
//      else if (sqlOnlyLogger.isInfoEnabled())
//      {
//        sqlOnlyLogger.info(sql);
//      }
//    }
//  }
//
//  /**
//   * Break an SQL statement up into multiple lines in an attempt to make it
//   * more readable
//   *
//   * @param sql SQL to break up.
//   * @return SQL broken up into multiple lines
//   */
//  private String processSql(String sql)
//  {
//    if (sql==null)
//    {
//      return null;
//    }
//
//    if (DriverSpy.TrimSql)
//    {
//      sql = sql.trim();
//    }
//
//    StringBuffer output = new StringBuffer();
//
//    if (DriverSpy.DumpSqlMaxLineLength <= 0)
//    {
//      output.append(sql);
//    }
//    else
//    {
//      // insert line breaks into sql to make it more readable
//      StringTokenizer st = new StringTokenizer(sql);
//      String token;
//      int linelength = 0;
//
//      while (st.hasMoreElements())
//      {
//        token = (String) st.nextElement();
//
//        output.append(token);
//        linelength += token.length();
//        output.append(" ");
//        linelength++;
//        if (linelength > DriverSpy.DumpSqlMaxLineLength)
//        {
//          output.append("\n");
//          linelength = 0;
//        }
//      }
//    }
//
//    if (DriverSpy.DumpSqlAddSemicolon)
//    {
//      output.append(";");
//    }
//
//    return output.toString();
//  }
//
//  /**
//   * Special call that is called only for JDBC method calls that contain SQL.
//   *
//   * @param spy        the Spy wrapping the class where the SQL occurred.
//   *
//   * @param execTime   how long it took the SQL to run, in milliseconds.
//   *
//   * @param methodCall a description of the name and call parameters of the
//   *                   method that generated the SQL.
//   *
//   * @param sql        SQL that occurred.
//   */
//  public void sqlTimingOccured(Spy spy, long execTime, String methodCall, String sql)
//  {
//    if (sqlTimingLogger.isErrorEnabled() &&
//        (!DriverSpy.DumpSqlFilteringOn || shouldSqlBeLogged(sql)))
//    {
//      if (DriverSpy.SqlTimingErrorThresholdEnabled &&
//          execTime >= DriverSpy.SqlTimingErrorThresholdMsec)
//      {
//        sqlTimingLogger.error(
//          buildSqlTimingDump(spy, execTime, methodCall, sql, true));
//      }
//      else if (sqlTimingLogger.isWarnEnabled())
//      {
//        if (DriverSpy.SqlTimingWarnThresholdEnabled &&
//          execTime >= DriverSpy.SqlTimingWarnThresholdMsec)
//        {
//          sqlTimingLogger.warn(
//            buildSqlTimingDump(spy, execTime, methodCall, sql, true));
//        }
//        else if (sqlTimingLogger.isDebugEnabled())
//        {
//          sqlTimingLogger.debug(
//            buildSqlTimingDump(spy, execTime, methodCall, sql, true));
//        }
//        else if (sqlTimingLogger.isInfoEnabled())
//        {
//          sqlTimingLogger.info(
//            buildSqlTimingDump(spy, execTime, methodCall, sql, false));
//        }
//      }
//    }
//  }
//
//  /**
//   * Helper method to quickly build a SQL timing dump output String for
//   * logging.
//   *
//   * @param spy        the Spy wrapping the class where the SQL occurred.
//   *
//   * @param execTime   how long it took the SQL to run, in milliseconds.
//   *
//   * @param methodCall a description of the name and call parameters of the
//   *                   method that generated the SQL.
//   *
//   * @param sql        SQL that occurred.
//   *
//   * @param debugInfo  if true, include debug info at the front of the output.
//   *
//   * @return a SQL timing dump String for logging.
//   */
//  private String buildSqlTimingDump(Spy spy, long execTime, String methodCall,
//    String sql, boolean debugInfo)
//  {
//    StringBuffer out = new StringBuffer();
//
//    if (debugInfo)
//    {
//      out.append(getDebugInfo());
//      out.append(nl);
//      out.append(spy.getConnectionNumber());
//      out.append(". ");
//    }
//
//    // NOTE: if both sql dump and sql timing dump are on, the processSql
//    // algorithm will run TWICE once at the beginning and once at the end
//    // this is not very efficient but usually
//    // only one or the other dump should be on and not both.
//
//    sql = processSql(sql);
//
//    out.append(sql);
//    out.append(" {executed in ");
//    out.append(execTime);
//    out.append(" msec}");
//
//    return out.toString();
//  }
//
//  /**
//   * Get debugging info - the module and line number that called the logger
//   * version that prints the stack trace information from the point just before
//   * we got it (net.sf.log4jdbc)
//   *
//   * if the optional log4jdbc.debug.stack.prefix system property is defined then
//   * the last call point from an application is shown in the debug
//   * trace output, instead of the last direct caller into log4jdbc
//   *
//   * @return debugging info for whoever called into JDBC from within the application.
//   */
//  private static String getDebugInfo()
//  {
//    Throwable t = new Throwable();
//    t.fillInStackTrace();
//
//    StackTraceElement[] stackTrace = t.getStackTrace();
//
//    if (stackTrace != null)
//    {
//      String className;
//
//      StringBuffer dump = new StringBuffer();
//
//      /**
//       * The DumpFullDebugStackTrace option is useful in some situations when
//       * we want to see the full stack trace in the debug info-  watch out
//       * though as this will make the logs HUGE!
//       */
//      if (DriverSpy.DumpFullDebugStackTrace)
//      {
//        boolean first=true;
//        for (int i = 0; i < stackTrace.length; i++)
//        {
//          className = stackTrace[i].getClassName();
//          if (!className.startsWith("net.sf.log4jdbc"))
//          {
//            if (first)
//            {
//              first = false;
//            }
//            else
//            {
//              dump.append("  ");
//            }
//            dump.append("at ");
//            dump.append(stackTrace[i]);
//            dump.append(nl);
//          }
//        }
//      }
//      else
//      {
//        dump.append(" ");
//        int firstLog4jdbcCall = 0;
//        int lastApplicationCall = 0;
//
//        for (int i = 0; i < stackTrace.length; i++)
//        {
//          className = stackTrace[i].getClassName();
//          if (className.startsWith("net.sf.log4jdbc"))
//          {
//            firstLog4jdbcCall = i;
//          }
//          else if (DriverSpy.TraceFromApplication &&
//            className.startsWith(DriverSpy.DebugStackPrefix))
//          {
//            lastApplicationCall = i;
//            break;
//          }
//        }
//        int j = lastApplicationCall;
//
//        if (j == 0)  // if app not found, then use whoever was the last guy that called a log4jdbc class.
//        {
//          j = 1 + firstLog4jdbcCall;
//        }
//
//        dump.append(stackTrace[j].getClassName()).append(".").append(stackTrace[j].getMethodName()).append("(").
//          append(stackTrace[j].getFileName()).append(":").append(stackTrace[j].getLineNumber()).append(")");
//      }
//
//      return dump.toString();
//    }
//    else
//    {
//      return null;
//    }
//  }
//
//  /**
//   * Log a Setup and/or administrative log message for log4jdbc.
//   *
//   * @param msg message to log.
//   */
//  public void debug(String msg)
//  {
//    debugLogger.debug(msg);
//  }
//
//  /**
//   * Called whenever a new connection spy is created.
//   *
//   * @param spy ConnectionSpy that was created.
//   */
//  public void connectionOpened(Spy spy)
//  {
//    if (connectionLogger.isDebugEnabled())
//    {
//      connectionLogger.info(spy.getConnectionNumber() + ". Connection opened " +
//        getDebugInfo());
//      connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump());
//    }
//    else
//    {
//      connectionLogger.info(spy.getConnectionNumber() + ". Connection opened");
//    }
//  }
//
//  /**
//   * Called whenever a connection spy is closed.
//   *
//   * @param spy ConnectionSpy that was closed.
//   */
//  public void connectionClosed(Spy spy)
//  {
//    if (connectionLogger.isDebugEnabled())
//    {
//      connectionLogger.info(spy.getConnectionNumber() + ". Connection closed " +
//        getDebugInfo());
//      connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump());
//    }
//    else
//    {
//      connectionLogger.info(spy.getConnectionNumber() + ". Connection closed");
//    }
//  }
//}
